//
//  ARLogManager.swift
//  AquaRaft
//
//  Created by 何启亮 on 2024/5/3.
//

import Foundation
import JKSwiftExtension

/// 事件上报单例
class ARLogManager: NSObject {
    
    // MARK: - Property
    
    /// 埋点缓存长度
    private let limitSize = 20
    /// 缓存
    private var cacheList: [ARLogStruct] = []
    /// 自增id
    private var serialId: Int = 0
    private let launcherId: String = {
        let str = "\(Date().timeIntervalSince1970)\(ARDevice.share.uuidResult.idfa ?? "")"
        return str.jk.md5Encrypt()
    }()
    
    /// 是否需要延迟上报
    private var isWaitingForSend = false
    
    /// 操作队列 - 串行
    private let queue = DispatchQueue(label: "ar.log.queue")
    private var timer: Timer?
    
    // MARK: - Shared
    
    static let shared = ARLogManager()
    private override init() {
        // Do nothing...
    }
    
    // MARK: - Action
    
    /// 快捷方法
    static func logPage(_ page: ARLogPage) {
        log(page: page.rawValue)
    }
    
    static func log(page: String?, subPage: String? = nil, terPage: String? = nil, broadcasterId: String? = nil) {
        shared.log(page: page, subPage: subPage, terPage: terPage, broadcasterId: broadcasterId)
    }
    
    /// 上报事件
    func log(page: String?, subPage: String? = nil, terPage: String? = nil, broadcasterId: String? = nil) {
        queue.async {
            var eventDict: [String: AnyDecodable] = [:]
            if let page = page {
                eventDict["page"] = .string(page)
            }
            if let subPage = subPage {
                eventDict["subPage"] = .string(subPage)
            }
            if let terPage = terPage {
                eventDict["terPage"] = .string(terPage)
            }
            if let broadcasterId = broadcasterId {
                eventDict["broadcasterId"] = .string(broadcasterId)
            }
            eventDict["duration"] = .int(0)
            eventDict["event"] = .string("pv")
            eventDict["tm"] = .double(Date().timeIntervalSince1970)
            
            let item = self._createLogItem(eventDict, logType: ARLogTypeStruct.globalBehavior)
            self.logStruct(item)
        }
    }
    
    /// 清空当前缓存，立即上传
    @objc func flush() {
        queue.async {
            self.isWaitingForSend = false
            if let timer = self.timer {
                self.timer = nil
                timer.invalidate()
            }
            
            if self.cacheList.isEmpty {
                return
            }
            
            let list = self.cacheList
            self.cacheList.removeAll()
            self._uploadLog(list)
        }
    }
    
    // MARK: Helper
    
    /// 添加一个event
    private func logStruct(_ struct: ARLogStruct) {
        
        /// 外部调用 - 由外部保证线程安全
        self.cacheList.append(`struct`)
        if self.cacheList.count >= self.limitSize {
            // 临界点
            self.flush()
            return
        }
        
        // 没到达临界点
        self.delayUpload()
    }
    
    /// 延迟上报的方法
    private func delayUpload() {
        if isWaitingForSend {
            return
        }
        
        isWaitingForSend = true
        if let timer = timer {
            self.timer = nil
            timer.invalidate()
        }
        DispatchQueue.main.async {
            let timer = Timer.scheduledTimer(timeInterval: 20.0, target: self, selector: #selector(self.flush), userInfo: nil, repeats: false)
            self.timer = timer
        }
    }
    
    /// 上报日志
    private func _uploadLog(_ cacheList: [ARLogStruct]) {
        // 目前先不做重新上报的逻辑
        ARLogRequest().uploadLog(cacheList) { err in
            if let err = err {
                debugPrint("Upload log err: \(err)")
                return
            }
            debugPrint("Upload log success")
        }
    }
    
    private func _createLogItem(_ event: [String: AnyDecodable], logType: ARLogTypeStruct) -> ARLogStruct {
        let secId = serialId
        serialId += 1
        return ARLogStruct(data: [.dictionary(event)], log_type: logType.logType, subtype: logType.subType, behavior: logType.behavior, lan_id: self.launcherId, sec_id: secId)
    }
    
}
